////////////////////////////////////////////////////////////////////////////////////////////////////
/// Copyright (c) 2009 - 2010 RacoonStudios
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy of this
/// software and associated documentation files (the "Software"), to deal in the Software
/// without restriction, including without limitation the rights to use, copy, modify, merge,
/// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
/// to whom the Software is furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all copies or
/// substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
/// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
/// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
/// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
/// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once
#ifndef dxquaternion_h__
#define dxquaternion_h__

#ifdef RE_USE_DX

#include "core/types.h"
#include "math/scalar.h"
#include "math/float4.h"

namespace Math
{
	class matrix;
	class float4;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \class	quaternion
	///
	/// \brief	Quaternion. 
	///
	/// \author	Markus
	/// \date	17.02.2010
	////////////////////////////////////////////////////////////////////////////////////////////////////
	__declspec(align(16))
	class quaternion
	{
	public:

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	quaternion()
		///
		/// \brief	Default constructor. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		////////////////////////////////////////////////////////////////////////////////////////////////////
		quaternion();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	quaternion(scalar x, scalar y, scalar z, scalar w)
		///
		/// \brief	Constructor. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	x	The x coordinate. 
		/// \param	y	The y coordinate. 
		/// \param	z	The z coordinate. 
		/// \param	w	The w. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		quaternion(scalar x, scalar y, scalar z, scalar w);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	quaternion(const float4 & rhs)
		///
		/// \brief	Constructor. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		quaternion(const float4 & rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	quaternion(XMVECTOR rhs)
		///
		/// \brief	Constructor. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		quaternion(XMVECTOR rhs);






		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void operator= (const float4 & rhs)
		///
		/// \brief	Copy operator. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void operator = (const float4 & rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void operator= (XMVECTOR rhs)
		///
		/// \brief	Copy operator. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void operator = (XMVECTOR rhs);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator== (const float4 & rhs) const
		///
		/// \brief	Equality operator. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		///
		/// \return	true if the parameters are considered equivalent. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator == (const float4 & rhs) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool operator!= (Const float4 & rhs) const
		///
		/// \brief	Inequality operator. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	rhs	The right hand side. 
		///
		/// \return	true if the parameters are not considered equivalent. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool operator != (const float4 & rhs) const;






		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void set(scalar x, scalar y, scalar z, scalar w)
		///
		/// \brief	Sets. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	x	The scalar to set. 
		/// \param	y	The scalar to set. 
		/// \param	z	The scalar to set. 
		/// \param	w	The scalar to set. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void set(scalar x, scalar y, scalar z, scalar w);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void set(const float4 & f)
		///
		/// \brief	Sets. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	f	The const float4 & to set. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void set(const float4 & f);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void setx(scalar x)
		///
		/// \brief	Setxes. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	x	The x coordinate. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void setx(scalar x);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void sety(scalar y)
		///
		/// \brief	Seties. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	y	The y coordinate. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void sety(scalar y);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void setz(scalar z)
		///
		/// \brief	Setzs. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	z	The z coordinate. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void setz(scalar z);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	void setw(scalar w)
		///
		/// \brief	Setws. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	w	The w. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		void setw(scalar w);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar & getx()
		///
		/// \brief	Getxes this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar & getx();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar & gety()
		///
		/// \brief	Geties this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar & gety();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar & getz()
		///
		/// \brief	Getzs this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar & getz();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar & getw()
		///
		/// \brief	Getws this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar & getw();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar getx() const
		///
		/// \brief	Xes this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar getx() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar gety() const
		///
		/// \brief	Ies this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar gety() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar getz() const
		///
		/// \brief	Zs this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar getz() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar getw() const
		///
		/// \brief	Ws this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar getw() const;






		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	bool isidentity() const
		///
		/// \brief	Query if this object isidentity. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	true if it succeeds, false if it fails. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		bool isidentity() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar length() const
		///
		/// \brief	Lengthes this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar length() const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	scalar lengthsq() const
		///
		/// \brief	Lengthsqs this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		scalar lengthsq() const;






		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion barycentric(const quaternion & q0, const quaternion & q1,
		/// 	const quaternion & q2, scalar f, scalar g)
		///
		/// \brief	Barycentrics. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q0	The 0. 
		/// \param	q1	The first const quaternion &. 
		/// \param	q2	The second const quaternion &. 
		/// \param	f	The. 
		/// \param	g	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion barycentric(const quaternion & q0, const quaternion & q1, const quaternion & q2, scalar f, scalar g);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion conjugate(const quaternion & q)
		///
		/// \brief	Conjugates. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion conjugate(const quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static scalar dot(const quaternion & q1, const quaternion & q2)
		///
		/// \brief	Dots. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q1	The first const quaternion &. 
		/// \param	q2	The second const quaternion &. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static scalar dot(const quaternion & q1, const quaternion & q2);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion exp(const quaternion & q)
		///
		/// \brief	Exps. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion exp(const quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion identity()
		///
		/// \brief	Identities this object. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion identity();

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion inverse(const quaternion & q)
		///
		/// \brief	Inverses. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion inverse(const quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion ln(const quaternion & q)
		///
		/// \brief	Lns. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion ln(const quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion multiply(const quaternion & q1, const quaternion & q2)
		///
		/// \brief	Multiplies. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q1	The first const quaternion &. 
		/// \param	q2	The second const quaternion &. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion multiply(const quaternion & q1, const quaternion & q2);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion normalize(const quaternion & q)
		///
		/// \brief	Normalizes. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion normalize(const quaternion & q);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion rotationaxis(const float4 & axis, scalar angle)
		///
		/// \brief	Rotationaxis. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	axis	The axis. 
		/// \param	angle	The angle. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion rotationaxis(const float4 & axis, scalar angle);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion rotationmatrix(const matrix & m)
		///
		/// \brief	Rotationmatrixes. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	m	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion rotationmatrix(const matrix & m);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion rotateionyawpitchroll(scalar yaw, scalar pitch, scalar roll)
		///
		/// \brief	Rotateionyawpitchrolls. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	yaw		The yaw. 
		/// \param	pitch	The pitch. 
		/// \param	roll	The roll. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion rotateionyawpitchroll(scalar yaw, scalar pitch, scalar roll);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion slerp(const quaternion & q1, const quaternion & q2, scalar s)
		///
		/// \brief	Slerps. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q1	The first const quaternion &. 
		/// \param	q2	The first const quaternion &. 
		/// \param	s	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion slerp(const quaternion & q1, const quaternion & q2, scalar s);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static void squadsetup(const quaternion & q1, const quaternion & q2,
		/// 	const quaternion & q3, const quaternion & q4, quatenrion & outA, quaternion & outB,
		/// 	quaternion & outC)
		///
		/// \brief	Squadsetups. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q1				The first const quaternion &. 
		/// \param	q2				The second const quaternion &. 
		/// \param	q3				The third const quaternion &. 
		/// \param	q4				The fourth const quaternion &. 
		/// \param [in,out]	outA	the out a. 
		/// \param [in,out]	outB	the out b. 
		/// \param [in,out]	outC	the out c. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static void squadsetup(const quaternion & q1, const quaternion & q2, const quaternion & q3, const quaternion & q4, quaternion & outA, quaternion & outB, quaternion & outC);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static quaternion squad(const quaternion & q1, const quaternion & q2,
		/// 	const quaternion & b, const quaternion c, scalar s)
		///
		/// \brief	Squads. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q1	The first const quaternion &. 
		/// \param	q2	The second const quaternion &. 
		/// \param	b	The. 
		/// \param	c	The. 
		/// \param	s	The. 
		///
		/// \return	. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static quaternion squad(const quaternion & q1, const quaternion & q2, const quaternion & b, const quaternion & c, scalar s);

		////////////////////////////////////////////////////////////////////////////////////////////////////
		/// \fn	static void toaxisangle(const quaternion & q, float4 & outAxis, scalar & outAngle)
		///
		/// \brief	Toaxisangles. 
		///
		/// \author	Markus
		/// \date	17.02.2010
		///
		/// \param	q					The. 
		/// \param [in,out]	outAxis		the out axis. 
		/// \param [in,out]	outAngle	the out angle. 
		////////////////////////////////////////////////////////////////////////////////////////////////////
		static void toaxisangle(const quaternion & q, float4 & outAxis, scalar & outAngle);

	protected:

		friend class matrix;


		XMVECTOR m_vec;

	private:

	};

}

#endif // RE_USE_DX

#endif // dxquaternion_h__